package com.autohammal.save;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import com.autohammal.save.util.SerializeUtil;

public class SaveContainer {

	private Map<Saveable, File> objMap = Collections
			.synchronizedMap(new HashMap<Saveable, File>());

	private String pathforSave = System.getProperty("user.dir");
	private byte[] token = new byte[1];

	private SaveContainer() {

	}

	public static SaveContainer newInstance() {
		return new SaveContainer();
	}

	private void add_(SaveEntry entry) {
		objMap.put(entry.getSaveable(), entry.getFile());
	}

	public void setPathforSave(String pathforSave) {
		this.pathforSave = pathforSave;
	}

	public static class SaveEntry {
		private Saveable saveable;
		private File file;

		private SaveEntry(Saveable saveable, File file) {
			this.saveable = saveable;
			this.file = file;
		}

		public static SaveEntry makeSaveEntry(Saveable saveable, File file) {
			return new SaveEntry(saveable, file);
		}

		public static SaveEntry makeSaveEntry(Saveable saveable) {
			return new SaveEntry(saveable, null);
		}

		public Saveable getSaveable() {
			return saveable;
		}

		public File getFile() {
			return file;
		}
	}

	public void add(SaveEntry... entrys) {
		if (entrys == null || entrys.length == 0)
			return;
		synchronized (token) {
			for (SaveEntry obj : entrys) {
				add_(obj);
			}
		}
	}

	public void save() {
		synchronized (token) {
			Collection<Saveable> saveables = filter();
			if (saveables != null) {
				for (Saveable saveable : saveables) {
					try {
						File file = objMap.get(saveable);
						file = file != null ? file : new File(pathforSave,
								saveable.getSaveName());
						SerializeUtil.serializeObject(saveable, file);
					} catch (FileNotFoundException e) {
						Logger.getLogger(getClass()).log(Level.ERROR, e);
					} catch (IOException e) {
						Logger.getLogger(getClass()).log(Level.ERROR, e);
					}
				}
			}
			objMap.clear();
		}
	}

	private Collection<Saveable> filter() {
		Collection<Saveable> saveables = objMap.keySet();
		if (filters != null) {
			for (SaveFilter filter : filters) {
				saveables = filter.getFilteredSaveable(saveables);
			}
		}
		return saveables;
	}

	public Object read(String fileName) {
		File file = new File(pathforSave, fileName);
		try {
			return SerializeUtil.unSerializeObject(file);
		} catch (FileNotFoundException e) {
			Logger.getLogger(getClass()).log(Level.ERROR, e);
		} catch (IOException e) {
			Logger.getLogger(getClass()).log(Level.ERROR, e);
		} catch (ClassNotFoundException e) {
			Logger.getLogger(getClass()).log(Level.ERROR, e);
		}
		return null;
	}

	public Object read(File file) {
		try {
			return SerializeUtil.unSerializeObject(file);
		} catch (FileNotFoundException e) {
			Logger.getLogger(getClass()).log(Level.ERROR, e);
		} catch (IOException e) {
			Logger.getLogger(getClass()).log(Level.ERROR, e);
		} catch (ClassNotFoundException e) {
			Logger.getLogger(getClass()).log(Level.ERROR, e);
		}
		return null;
	}

	private Set<SaveFilter> filters = null;

	public boolean addSaveFilter(SaveFilter filter) {
		if (filters == null) {
			filters = new HashSet<SaveFilter>();
		}
		return filters.add(filter);
	}

	public boolean removeSaveFilter(SaveFilter filter) {
		if (filters == null) {
			return filters.remove(filter);
		}
		return false;
	}

	public void clearSaveFilters() {
		if (filters == null) {
			filters.clear();
		}
	}
}
